/*
* Copyright (c) 2007 by Kirill Kolodyazhniy.
* See the file "license.terms" for information on usage and redistribution.
*/

#ifndef M_SOLID_H
#define M_SOLID_H

#include "physictools.h"
#include "shapedata.h"
#include "scenenode.h"
#include "matrix4.h"
#include "hasslots.h"

#include <string>


namespace Engine
{
	/**
	*   Physical objects in a simulation.
	*/
	class Solid
	{
	public:
		friend class PhysicSystem;

		typedef std::vector<Force> ForceVector;

		/**
		*   Constructor.
		*/
		Solid(const std::string& name, SceneNodePtr node);

		/**
		*   Destructor
		*/
		virtual ~Solid();

		/**
		*   Return name.
		*/
		const std::string& GetName()const{return m_name;}

		/**
		*   Returns true if the Solid is enabled.
		*/
		virtual bool IsEnabled() const = 0;

		/**
		*   Sets whether the Solid can collide with other Solids and be physically simulated.
		*   Forces applied to this Solid while disabled will be ignored.
		*/
		virtual void SetEnabled(bool e) = 0;

		/**
		*   Returns true if this is a static Solid.
		*/
		virtual bool IsStatic() const = 0;

		/**
		*   Sets whether the Solid should be static or dynamic.
		*/
		virtual void SetStatic(bool s) = 0;

		/**
		*   Returns whether the Solid is affected by gravity.
		*/
		virtual bool IsGravityEnabled()const = 0;

		/**
		*   Sets whether the Solid is affected by gravity.
		*/
		virtual void SetGravityEnabled(bool e) = 0;

		/**
		*   Removes the Solid from its current Space and adds it to the new Space.
		*/
		virtual void SetSpace(SpacePtr space) = 0;

		/**
		*   Sets this Solid's transform matrix.
		*/
		void SetTransform(const Matrix4<REAL>& t);

		/**
		*   Returns a constant reference to this Solid's transform.
		*/
		const Matrix4<REAL>& GetTransform() const;

		/**
		*   Adds a Shape to this Solid.
		*/
		void AddShape(const ShapeData& shape);

		/**
		*   Applies a force/torque to this Solid.  If the Solid is disabled, the Solid is static,
		*   or the magnitude of the force/torque is zero, this will do nothing.
		*/
		void AddForce(const Force& f);

		/**
		*   Removes all forces and torques currently affecting this Solid.
		*/
		void ZeroForces();

		/**
		*   Set a new mass, center, and intertia for the solid.
		*/
		virtual void SetMass(const Mass& newmass) = 0;

		/**
		*   Returns the Solid's mass.  This will return 0 if the Solid is static.
		*/
		virtual REAL GetMass() const = 0;

	protected:

		/**
		*   Update scene node transformation;
		*/
		void UpdateTransform();

	private:

		/**
		*   Loop over forces and apply.
		*/
		void ApplyForces(REAL step);

		/**
		*   Implementation of force applying.
		*/
		virtual void ApplyForce(const Force& f) = 0;

		/**
		*   Implementation of adding shape
		*/
		virtual void AddShapeImpl(const ShapeData& shape) = 0;

		/**
		*   Returns a constant reference to this Solid's transform from physic engine.
		*/
		virtual Matrix4<REAL> GetTransformImpl() const = 0;

		/**
		*   Set Solid's transform to physic engine.
		*/
		virtual void SetTransformImpl(const Matrix4<REAL>& t) = 0;

		/**
		*   Removes all forces and torques currently affecting this Solid.
		*/
		virtual void ZeroForcesImpl() = 0;
	private:

		std::string m_name;
		SceneNodePtr m_node;
		ForceVector m_forces;
	};
}

#endif
